package com.fla.minskmap;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.Comparator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

public class MainWindow extends JFrame {
    private static final long serialVersionUID = 6988233084543771610L;

    private final NumberFormat FORMATTER = NumberFormat.getInstance();

    private MapPanel mapPanel;

    private String distanceDimension;

    public MainWindow() {
        init();
    }

    public static void main(String[] args) {
        MainWindow mainWindow = new MainWindow();
        mainWindow.setVisible(true);
    }

    public void init() {
        setTitle("Minsk map");
        createMenu();

        int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
        int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;

        setSize((int) (screenWidth * 0.8), (int) (screenHeight * 0.8));
        setLocation((int) (screenWidth * 0.1), (int) (screenHeight * 0.1));

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBackground(Color.gray);

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout());
        getContentPane().add(topPanel);

        final JScrollPane scrollPane = new JScrollPane();
        scrollPane.getViewport().add(mapPanel = createMapPanel());
        topPanel.add(scrollPane, BorderLayout.CENTER);

        MouseAdapter mouseScroller = new MouseScroller();
        mapPanel.addMouseMotionListener(mouseScroller);
        mapPanel.addMouseListener(mouseScroller);

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            SwingUtilities.updateComponentTreeUI(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createMenu() {
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu optionsMenu = new JMenu("Options");
        menuBar.add(optionsMenu);

        JMenuItem showDistancesAction = new JMenuItem("Show distances");
        optionsMenu.add(showDistancesAction);

        showDistancesAction.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Map<String, Float> distances = mapPanel.getDistances();
                ValueComparator distanceComparator = new ValueComparator(distances);
                Map<String, Float> sortedMapap = new TreeMap<String, Float>(distanceComparator);

                sortedMapap.putAll(distances);
                
                StringBuilder distancesString = new StringBuilder();
                distancesString.append("id - id");
                distancesString.append("   ...   ");
                distancesString.append(String.format("distance in %ss", distanceDimension));
                distancesString.append('\n');
                for (String key : sortedMapap.keySet()) {
                    distancesString.append(key);
                    distancesString.append("   ...   ");
                    distancesString.append(FORMATTER.format(sortedMapap.get(key)));
                    distancesString.append('\n');
                }

                JOptionPane.showMessageDialog(null, distancesString);
            }
        });
    }

    private MapPanel createMapPanel() {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("config.properties"));
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, "Cannot read the file config.properties");
        }

        String mapFileName = properties.getProperty("map_file_name");
        distanceDimension = properties.getProperty("distance_dimension");
        String numerator = properties.getProperty("numerator").replaceAll(",", ".");
        String denominator = properties.getProperty("denominator").replaceAll(",", ".");

        Icon image = new ImageIcon(mapFileName);
        return new MapPanel(image, distanceDimension, Float.valueOf(numerator), Float.valueOf(denominator));
    }
    
    private class MouseScroller extends MouseAdapter {
        private int oldX;
        private int oldY;
        
        private boolean firstClick = true;

        public void mouseDragged(MouseEvent e) {
            JComponent component = (JComponent) e.getSource();
            
            int deltaX = firstClick ? 0 : oldX - e.getXOnScreen();
            int deltaY = firstClick ? 0 : oldY - e.getYOnScreen();
            
            firstClick = false;

            oldX = e.getXOnScreen();
            oldY = e.getYOnScreen();

            Rectangle oldRect = component.getVisibleRect();
            Rectangle result = new Rectangle(oldRect.x + deltaX, oldRect.y + deltaY, oldRect.width, oldRect.height);

            component.scrollRectToVisible(result);
        }
        @Override
        public void mousePressed(MouseEvent e) {
            firstClick = true;
        }
    }
    
    private class ValueComparator implements Comparator {

        Map base;

        public ValueComparator(Map base) {
            this.base = base;
        }

        public int compare(Object a, Object b) {

            if ((Float) base.get(a) < (Float) base.get(b)) {
                return -1;
            } else if ((Float) base.get(a) == (Float) base.get(b)) {
                return 0;
            } else {
                return 1;
            }
        }
    }
}
